/*
 *    Copyright © OpenAtom Foundation.
 *
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 */

package com.inspur.edp.bff.core.action.query;

import com.inspur.edp.bef.api.lcp.IStandardLcp;
import com.inspur.edp.bef.auditconfig.api.BefAuditConfigService;
import com.inspur.edp.bef.auditconfig.entity.BefAuditConfig;
import com.inspur.edp.bef.auditconfig.entity.BefAuditConfigItem;
import com.inspur.edp.bff.api.dataprocessor.IDataConvertor;
import com.inspur.edp.bff.api.dataprocessor.IFilterFieldConvertor;
import com.inspur.edp.bff.api.exception.BffFrameworkException;
import com.inspur.edp.bff.api.exception.ErrorCodes;
import com.inspur.edp.bff.api.extend.IBffManagerExtend;
import com.inspur.edp.bff.api.manager.context.DataMapperContext;
import com.inspur.edp.bff.api.manager.context.QueryContext;
import com.inspur.edp.bff.core.manager.ActionConstant;
import com.inspur.edp.bff.core.manager.FSManagerContext;
import com.inspur.edp.bff.spi.AbstractFSAction;
import com.inspur.edp.bff.spi.event.query.BffQueryEventBroker;
import com.inspur.edp.cef.entity.condition.EntityFilter;
import com.inspur.edp.cef.entity.condition.FilterCondition;
import com.inspur.edp.cef.entity.condition.SortCondition;
import com.inspur.edp.cef.entity.entity.IEntityData;
import io.iec.edp.caf.audit.api.data.AuditType;
import io.iec.edp.caf.audit.api.data.EventResultType;
import io.iec.edp.caf.audit.api.data.GspAudit;
import io.iec.edp.caf.audit.api.manager.GspAuditManager;
import io.iec.edp.caf.boot.context.CAFContext;
import io.iec.edp.caf.commons.utils.SpringBeanUtils;
import lombok.var;

import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;

public class QueryAction extends AbstractFSAction<ArrayList<IEntityData>> {

    private EntityFilter filter;
    private Map<String, String> filterMap = new HashMap<>();

    public QueryAction(EntityFilter filter) {
        this.filter = filter;
    }

    private void transFilter() {
        if (filter == null) {
            return;
        }

        IFilterFieldConvertor convertor = getContext().getFilterConvertor();
        if (convertor == null) {
            return;
        }
        if (filter.getFilterConditions() != null && filter.getFilterConditions().size() > 0) {

            transFilter(filter.getFilterConditions(), convertor);
        }
        if (filter.getSortConditions() != null && filter.getSortConditions().size() > 0) {

            transSort(filter.getSortConditions(), convertor);
        }
    }

    private void transFilter(ArrayList<FilterCondition> filterConditions, IFilterFieldConvertor convertor) {
        for (FilterCondition filterCondition : filterConditions) {
            if ("".equals(filterCondition.getFilterField()) || filterCondition.getFilterField() == null) {
                throw new BffFrameworkException(ErrorCodes.BFF_FRAMEWORK_1003);
            }
            filterCondition.setFilterField(convertor.transFilterField(filterCondition.getFilterField()));
            if (filterCondition.getFilterNode() != null && "".equals(filterCondition.getFilterNode()) == false) {

                filterCondition.setFilterNode(getContext().getBECodeFromVM(getContext().getVoCode(filterCondition.getFilterNode())));
            }
        }
    }

    private void transSort(ArrayList<SortCondition> sortConditions, IFilterFieldConvertor convertor) {
        for (SortCondition sortCondition : sortConditions) {
            if ("".equals(sortCondition.getSortField()) || sortCondition.getSortField() == null) {
                throw new BffFrameworkException(ErrorCodes.BFF_FRAMEWORK_1004);
            }
            sortCondition.setSortField(convertor.transFilterField(sortCondition.getSortField()));
        }
    }

    @Override
    protected void execute() {
        transFilter();
        if (getContext().getAssemblerManager() == null) {
            doDefaultQuery();
            return;
        }

        QueryContext queryContext = new QueryContext();
        queryContext.setFilter(filter);
        setQueryContext(queryContext);

        //① BeforeQuery
        getContext().getAssemblerManager().getQueryAssembler().doBeforeQuery(getContext(), queryContext);
        //② DoQuery
        HashMap<String, ArrayList<IEntityData>> queryResult = getContext().getAssemblerManager().
                getQueryAssembler().doQuery(getContext(), queryContext);
        //③ DataMapping
        DataMapperContext mapperContext = new DataMapperContext();
        mapperContext.setSourceData(queryResult);
        ArrayList<IEntityData> vmDatas = getContext().getAssemblerManager().
                getDataMapperAssembler().doDataMapping2Vo(getContext(), mapperContext);

//        dealExtendMapping(vmDatas);
        queryContext.setQueryResult(vmDatas);
        //④ AfterQuery
        getContext().getAssemblerManager().getQueryAssembler().doAfterQuery(getContext(), queryContext);
        setResult(vmDatas);
        auditLog(queryResult);
    }

    private void auditLog(HashMap<String, ArrayList<IEntityData>> queryResult) {
        if (getContext().getVoId() == null || getContext().getVoId().equals(""))
            return;

        List<BefAuditConfig> list = SpringBeanUtils.getBean(BefAuditConfigService.class).getBefAuditConfigsByVoId(this.getContext().getVoId());
        if (list == null || list.size() == 0)
            return;
        for (BefAuditConfig config : list) {
            auditItem(config, queryResult);
        }
    }

    private void auditItem(BefAuditConfig auditConfig, HashMap<String, ArrayList<IEntityData>> queryResult) {
        if (auditConfig.getConfigItems() == null || auditConfig.getConfigItems().size() == 0)
            return;
        for (var item : auditConfig.getConfigItems()) {
            if (!ActionConstant.QueryActionId.equals(item.getTargetVoActionId()))
                continue;
            GspAudit gspAudit = new GspAudit();
            gspAudit.setId(UUID.randomUUID().toString());
            gspAudit.setCategoryId(item.getAuditTypeId());
            gspAudit.setEventId(item.getAuditEventId());
            gspAudit.setDateTime(new Date());
            gspAudit.setType(AuditType.message);
            gspAudit.setEventResult(EventResultType.success);
            gspAudit.setGspAuditData(new ArrayList<>());
            gspAudit.setDescription(item.getAuditMessage().getAuditMessage());
            if (CAFContext.current.getFrameworkContext() != null) {
                gspAudit.setFunctionId(CAFContext.current.getFrameworkContext().getFuncId());
                gspAudit.setFunctionCode(CAFContext.current.getFrameworkContext().getFuncCode());
                if (CAFContext.current.getFrameworkContext().getItems().containsKey("menuName"))
                    gspAudit.setFunctionName(
                            String.valueOf(
                                    CAFContext.current.getFrameworkContext().getItems().get("menuName")));
            }
            setAuditMessage(gspAudit, item, queryResult);
            SpringBeanUtils.getBean(GspAuditManager.class).addAuditSync(gspAudit);
        }
    }

    private void setAuditMessage(GspAudit gspAudit, BefAuditConfigItem item,
                                 HashMap<String, ArrayList<IEntityData>> vmDatas) {
        Map<String, List<String>> auditMessageDataFields = new HashMap<>();
        Map<String, Map<String, List<String>>> childAuditMessageDataFields = new HashMap<>();
        AuditUtils.getAuditMessageField(gspAudit, item, auditMessageDataFields, childAuditMessageDataFields);
        for (Map.Entry<String, ArrayList<IEntityData>> data : vmDatas.entrySet()) {
            if (data.getValue() != null)
                for (IEntityData dataItem : data.getValue())
                    AuditUtils.addAuditMessageFieldValue(dataItem, "", auditMessageDataFields, childAuditMessageDataFields, this.getContext());
        }
        AuditUtils.setAuditMessage(gspAudit, auditMessageDataFields, childAuditMessageDataFields);
    }


    private void dealExtendMapping(ArrayList<IEntityData> voDatas) {
        var extList = ((FSManagerContext) getContext()).getExtList();
        if (extList == null || extList.size() < 1)
            return;
        for (var voData : voDatas) {
            var beData = getLcp().retrieve(voData.getID()).getData();
            dealExtendMapping(voData, beData, extList);
        }

    }

    private void dealExtendMapping(IEntityData voData, IEntityData beData, List<IBffManagerExtend> extList) {
        for (var ext : extList) {
            ext.mapData2Vo(voData, beData);
        }
    }

    protected void setQueryContext(QueryContext queryContext) {
    }

    protected IStandardLcp getQueryLcp() {
        return getLcp();
    }


    private void doDefaultQuery() {
        try {
            List<IEntityData> queryResult = getQueryLcp().query(filter);
            BffQueryEventBroker.firebeforeWKZTotalCoreQuery(filter);
            if (queryResult == null) {
                setResult(null);
            } else {
                ArrayList<IEntityData> vmDatas = new ArrayList<IEntityData>();
                IDataConvertor dataConvertor = getContext().getDataConvertor();
                for (IEntityData entityData : queryResult) {
                    IEntityData vmData = getContext().createData();
                    dataConvertor.convertFromBEData(entityData, vmData);
                    vmDatas.add(vmData);
                }
                BffQueryEventBroker.fireafterWKZTotalCoreQuery(getContext(), queryResult, vmDatas);
                setResult(vmDatas);
            }
        } catch (Exception e) {
            BffQueryEventBroker.fireQueryUnnormalStop(e);
            throw e;
        }
    }

}
